package com.specificgroup.jira.plugin.acpro.action;

import com.atlassian.plugin.webresource.WebResourceManager;
import com.specificgroup.jira.plugin.acpro.Constants;
import com.specificgroup.jira.plugin.acpro.exception.AcproException;
import com.specificgroup.jira.plugin.acpro.mapping.AcproUser;
import com.specificgroup.jira.plugin.acpro.mapping.JiraUser;
import com.specificgroup.jira.plugin.acpro.mapping.NotifyCCUser;
import com.specificgroup.jira.plugin.acpro.mapping.UserMappingData;
import com.specificgroup.jira.plugin.acpro.model.Settings;
import com.specificgroup.jira.plugin.acpro.service.AcproManager;
import com.specificgroup.jira.plugin.acpro.service.JiraAcproPluginJiraManager;
import com.specificgroup.jira.plugin.acpro.session.SessionTempData;
import com.specificgroup.jira.plugin.acpro.session.SessionUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author Ivan Holub
 */
public class UserMappingAction extends AcproActionSupport {

    private static final String NEXT_ACTION = "AcproIssueMapping!default.jspa";

    private static final String RESOURCE_KEY = "com.specificgroup.jira.plugin.acpro.jira-acpro-plugin:acpro-resource-js-user-mapping";

    private static final String USER_PARAMETER_NAME = "userMapping";

    private static final String NOTIFY_CC_PARAMETER_NAME = "notifyCCMapping";

    private Logger log = Logger.getLogger(getClass());

    private AcproManager acproManager;

    private UserMappingData userMappingData;

    private WebResourceManager webResourceManager;

    private Map<String, String> userMappingStr;

    private Map<String, String> notifyCCMappingStr;

    private JiraAcproPluginJiraManager jiraAcproPluginJiraManager;

    public UserMappingData getUserMappingData() {
        return userMappingData;
    }

    public UserMappingAction(AcproManager acproManager, JiraAcproPluginJiraManager jiraAcproPluginJiraManager,
                             WebResourceManager webResourceManager) {
        this.acproManager = acproManager;
        this.jiraAcproPluginJiraManager = jiraAcproPluginJiraManager;
        this.webResourceManager = webResourceManager;
    }

    @Override
    public String doDefault() throws Exception {
        if (!hasPermissions()) {
            return PERMISSION_VIOLATION_RESULT;
        }

        webResourceManager.requireResource(RESOURCE_KEY);
        webResourceManager.requireResource(Constants.JQUERY_RESOURCE_KEY);

        Settings settings = SessionUtil.getSettings();
        try {
            userMappingData = acproManager.prepareUserMapping(settings);
        } catch (IOException e) {
            log.error("Error", e);
            addErrorMessage(e.toString());
            return ERROR;
        } catch (AcproException e) {
            log.error("Error", e);
            addErrorMessage(e.getMessage());
            return ERROR;
        }

        SessionTempData sessionTempData = SessionUtil.getSessionTempData();
        sessionTempData.setUserMappingData(userMappingData);

        return super.doDefault();
    }

    @Override
    protected String doExecute() throws Exception {
        if (!hasPermissions()) {
            return PERMISSION_VIOLATION_RESULT;
        }
        
        Settings settings = SessionUtil.getSettings();
        settings.setUsersMapping(userMappingStr);
        settings.setNotifyCCMapping(notifyCCMappingStr);

        String redirect = getRedirect(NEXT_ACTION);
        return redirect;
    }

    @Override
    protected void doValidation() {
        boolean hasErrors = false;
        //from session
        UserMappingData userMappingData = SessionUtil.getSessionTempData().getUserMappingData();

        Map<String, JiraUser> jiraUsers = jiraAcproPluginJiraManager.getJiraUsersMap(); //jira users

        userMappingStr = new HashMap<String, String>(); //acpro user key -> jira user name
        for (AcproUser acproUser: userMappingData.getAcproUsers()) {
            String userKey = acproUser.getUserKey();
            String jiraUserName = request.getParameter(USER_PARAMETER_NAME + userKey);
            if (!isJiraUserNameValid(jiraUsers, jiraUserName)) {
                hasErrors = true;
                addErrorMessage(getText("error.selectUser", acproUser.getUserID()));
            } else {
                userMappingStr.put(userKey, jiraUserName);
            }
        }
        notifyCCMappingStr = new HashMap<String, String>(); //acpro notifyCC email -> jira user name
        for (NotifyCCUser notifyCCUser: userMappingData.getNotifyCCUsers()) {
            String userId = notifyCCUser.getId();
            String email = notifyCCUser.getEmail();
            String jiraUserName = request.getParameter(NOTIFY_CC_PARAMETER_NAME + userId);
            if (!isJiraUserNameValid(jiraUsers, jiraUserName)) {
                hasErrors = true;
                addErrorMessage(getText("error.selectNotifyCC", email));
            } else {
                notifyCCMappingStr.put(email, jiraUserName);
            }
        }

        if (hasErrors) {
            webResourceManager.requireResource(RESOURCE_KEY);
            webResourceManager.requireResource(Constants.JQUERY_RESOURCE_KEY);

            Map<String, JiraUser> usersMapping = userMappingData.getUsersMapping();
            usersMapping.clear();

            for (String acproUserKey: userMappingStr.keySet()) {
                String jiraUserName = userMappingStr.get(acproUserKey); //jira user name
                JiraUser jiraUser = jiraUsers.get(jiraUserName);
                usersMapping.put(acproUserKey, jiraUser);
            }

            Map<String, JiraUser> notifyCCMapping = userMappingData.getNotifyCCMapping();
            notifyCCMapping.clear();

            for (String notifyCCUserEmail: notifyCCMappingStr.keySet()) { //notifyCC emails
                NotifyCCUser notifyCCUser = findNotifyCCUserByEmail(userMappingData, notifyCCUserEmail);
                String jiraUserName = notifyCCMappingStr.get(notifyCCUserEmail); //jira user name
                JiraUser jiraUser = jiraUsers.get(jiraUserName);
                notifyCCMapping.put(notifyCCUser.getId(), jiraUser);
            }

            //show form again
            this.userMappingData = userMappingData;
        }

        super.doValidation();
    }

    private boolean isJiraUserNameValid(Map<String, JiraUser> jiraUsers, String userName) {
        return StringUtils.isNotEmpty(userName) && jiraUsers.containsKey(userName);
    }

    private NotifyCCUser findNotifyCCUserByEmail(UserMappingData userMappingData, String email) {
        for (NotifyCCUser user: userMappingData.getNotifyCCUsers()) {
            if (email.equals(user.getEmail())) {
                return user;
            }
        }
        return null;
    }

}
